package org.oschina.api.user.user.dao;

import java.util.List;
import org.oschina.Constants;
import org.oschina.api.BaseDAO;
import org.oschina.api.user.user.model.User;
import org.oschina.api.user.user.vo.UserSearchVo;
import org.oschina.api.user.user.vo.UserVo;
import org.oschina.helper.cache.ICachePipeline;
import org.springframework.stereotype.Repository;

@Repository
public class UserDAO extends BaseDAO {
	
	private final String find[]={"id","account","username","password","headphoto","role","follow_count","fans_count","online","last_login"};
	private final String findVo[]={"id","username","headphoto","signature","follow_count","fans_count","online","last_login"};
	
	private final int UPLOAD_ROLE_BATCH_COUNT=50;
	
	/**
	 * 创建用户
	 * @param user
	 * @return
	 */
	public User create(User user)
	{
		getQueryHelper().insert(new String[]{"id","account","username","password","signature","headphoto","type","role","follow_count","fans_count","last_login","online","register_ip","register_identity","register_time"}, 
				new Object[]{user.getId(),user.getAccount(),user.getUsername(),user.getPassword(),user.getSignature(),user.getHeadphoto(),user.getType(),
				user.getRole(),user.getFollow_count(),user.getFans_count(),user.getRegister_time(),user.getOnline(),user.getRegister_ip(),
				user.getRegister_identity(),user.getRegister_time()},UserVo.class);
		return user;
	}
	
	/**
	 * 根据账号和类型返回 只返回ID,用户名,密码,角色,在线,令牌
	 * @param account
	 * @return
	 */
	public User findByAccountAndType(String account,int type)
	{
		return (User)getQueryHelper().queryForObject(new String[]{"id","username","password","token","role","online"}, 
				new String[]{"type=?","account=?"},
				new Object[]{type,account}, User.class);
	}
	
	/**
	 * 根据令牌返回 只返回ID,账号,密码
	 * @param token
	 * @return
	 */
	public User findByToken(String token)
	{
		return (User)getQueryHelper().queryForObject(new String[]{"id","account","password"}, 
				new String[]{"token=?"},
				new Object[]{token}, User.class);
	}
	
	/**
	 * 根据账号 只返回ID,用户名,密码,角色,在线
	 * @param account
	 * @return
	 */
	public User findByAccount(String account)
	{
		return (User)getQueryHelper().queryForObject(new String[]{"id","username","password","role","online"}, 
				new String[]{"account=?"},
				new Object[]{account}, User.class);
	}
	
	/**
	 * 根据注册验证和类型返回 只返回ID,用户名,密码,角色
	 * @param account
	 * @return
	 */
	public User findByRegisterIdentityAndType(String identity,int type)
	{
		return (User)getQueryHelper().queryForObject(new String[]{"id","username","password","role"}, 
				new String[]{"type=?","register_identity=?"},
				new Object[]{type,identity}, User.class);
	}
	
	/**
	 * 根据用户名和类型返回
	 * @param username
	 * @return
	 */
	public UserVo findVoByUsernameAndType(String username,int type)
	{
		return (UserVo) getQueryHelper().queryForObject(findVo, new String[]{"type=?","username=?"}, new Object[]{type,username}, UserVo.class);
	}

	/**
	 * 搜索
	 * @param account
	 * @param username
	 * @param first
	 * @param max
	 * @return
	 */
	public List<UserSearchVo> search(String account,String username,int first,int max)
	{
		return getQueryHelper().query(Constants.DB_USER, 
				new String[]{"id","account","username","online","role","last_login","register_time"}, 
				new String[]{"account LIKE ?","username LIKE ?"}, null, new Object[]{account+"%",username+"%"}, UserSearchVo.class, first, max);
	}
	
	/**
	 * 返回数量
	 * @param account
	 * @param username
	 * @return
	 */
	public int getCountByAccountAndUsername(String account,String username)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"account LIKE ?","username LIKE ?"}, new Object[]{account+"%",username+"%"}, UserVo.class);
	}
	
	/**
	 * 根据角色返回在线数量
	 * @param role
	 * @return
	 */
	public int getCountByOnlineAndRole(int role)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"online=?","role=?"}, new Object[]{true,role}, UserVo.class);
	}
	
	/**
	 * 根据角色返回在线用户ID
	 * @param role
	 * @param first
	 * @param max
	 * @return
	 */
	public List<Integer> findIdByOnlineAndRole(int role,int first,int max)
	{
		return getQueryHelper().query(Constants.DB_USER, new String[]{"id"}, new String[]{"online=?","role=?"}, null, new Object[]{true,role}, Integer.class, first, max);
	}
	
	/**
	 * 返回在线数量
	 * @return
	 */
	public int getCountByOnline()
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"online=?"}, new Object[]{true}, UserVo.class);
	}
	
	/**
	 * 返回在线用户ID
	 * @param first
	 * @param max
	 * @return
	 */
	public List<Integer> findIdByOnline(int first,int max)
	{
		return getQueryHelper().query(new String[]{"id"}, new String[]{"online=?"}, null, new Object[]{true}, Integer.class, first, max);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public UserVo findVoById(int id)
	{
		UserVo user=_findVoByCache(id);
		if(user!=null)
			return user;
		
		if(isOnline(id))
			return (UserVo)getQueryHelper().queryForObject_cache(findVo, new String[]{"id=?"}, new Object[]{id}, UserVo.class);
		else
			return (UserVo)getQueryHelper().queryForObject(findVo, new String[]{"id=?"}, new Object[]{id}, UserVo.class);
	}
	private UserVo _findVoByCache(int id)
	{
		return (UserVo) getCacheHelper().hget(getIdKey(id),UserVo.class);
	}
	public boolean isInCache(int id)
	{
		return getCacheHelper().exists(getIdKey(id));
	}
	public boolean isOnline(int id)
	{
		return getCacheHelper().exists(getOnlineUserKey(id));
	}
	/**
	 * 清除用户资料相关缓存
	 * @param user
	 */
	public void removeCache(int user)
	{
		//getCacheHelper().del(getIdKey(user));
	}
	
	/**
	 * 放入在线缓存
	 * @param user
	 */
	public void putOnlineCache(User user)
	{
		getCacheHelper().hset(getOnlineUserKey(user.getId()), user, User.class, Constants.TIMEOUT_ONLINE_USER);
	}
	
	/**
	 * 获得在线缓存
	 * @param id
	 * @return
	 */
	public User getOnlineCache(int id)
	{
		return (User) getCacheHelper().hget(getOnlineUserKey(id),User.class);
	}
	
	/**
	 * 刷新在线缓存
	 * @param user
	 * @param lastPost
	 */
	public void refreshLastPostCache(int user,long lastPost)
	{
		getCacheHelper().hset(getOnlineUserKey(user),"last_post",lastPost,Constants.TIMEOUT_ONLINE_USER);
	}
	
	/**
	 * 清除在线缓存
	 * @param id
	 */
	public void removeOnlineCache(int id)
	{
		User user=getOnlineCache(id);
		if(user!=null)
			getCacheHelper().del(getOnlineUserKey(id));
	}
	
	private String getOnlineUserCache()
	{
		return Constants.CACHE_ONLINE_USER;
	}
	
	private String getOnlineUserKey(int id)
	{
		return getKey(getOnlineUserCache(), id);
	}
	
	/**
	 * 更新令牌
	 * @param id
	 * @param token
	 */
	public int updateToken(int id,String token)
	{
		return (int) getQueryHelper().update(new String[]{"token=?"}, new String[]{"id=?"}, new Object[]{token,id} ,User.class);
	}
	
	/**
	 * 清空令牌
	 * @param id
	 * @return
	 */
	public int clearToken(int id)
	{
		return (int) getQueryHelper().update(new String[]{"token=?"}, new String[]{"id=?"}, new Object[]{null,id}, User.class);
	}
	
	/**
	 * 更新在线状态
	 * @param id
	 * @param online
	 */
	public void updateOnline(int id,boolean online)
	{
		batchUpdate_queue("UPDATE "+Constants.DB_USER+" SET online=? WHERE id=?", new Object[]{online,id});
	}
	
	/**
	 * 更新最后登录时间
	 * @param id
	 * @param time
	 */
	public void updateLastLogin(int id,long time)
	{
		batchUpdate_queue("UPDATE "+Constants.DB_USER+" SET last_login=? WHERE id=?", new Object[]{time,id});
	}
	
	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	public int updateType(int id,int type)
	{
		return (int) getQueryHelper().update(new String[]{"type=?"}, new String[]{"id=?"}, new Object[]{type,id}, UserVo.class);
	}
	
	/**
	 * 更新密码
	 * @param id
	 * @param password
	 * @return
	 */
	public int updatePassword(int id,String password)
	{
		if(isOnline(id))
			getCacheHelper().hset(getOnlineUserKey(id), "password", password, Constants.TIMEOUT_ONLINE_USER);
		
		return (int) getQueryHelper().update(new String[]{"password=?"}, new String[]{"id=?"}, new Object[]{password,id}, UserVo.class);
	}
	
	/**
	 * 编辑
	 * @param user
	 * @return
	 */
	public int edit(User user)
	{
		updateCache(user.getId(),
				new String[]{"username","headphoto","signature"},
				new Object[]{user.getUsername(),user.getHeadphoto(),user.getSignature()});
		
		return (int) getQueryHelper().update(new String[]{"username=?","headphoto=?","signature=?"},
				new String[]{"id=?"},
				new Object[]{user.getUsername(),user.getHeadphoto(),user.getSignature(),user.getId()}, UserVo.class);
	}
	
	/**
	 * 更新角色
	 * @param id
	 * @param role
	 * @return
	 */
	public int updateRole(int id,int role)
	{
		if(isOnline(id))
			getCacheHelper().hset(getOnlineUserKey(id), "role", role, Constants.TIMEOUT_ONLINE_USER);
		
		return (int) getQueryHelper().update(new String[]{"role=?"}, new String[]{"id=?"}, new Object[]{role,id}, UserVo.class);
	}
	
	/**
	 * 根据角色更新
	 * @param source
	 * @param target
	 * @return
	 */
	public int updateRoleByRole(int source,int target)
	{
		int sum=getCountByOnlineAndRole(source);
		if(sum!=0)
		{
			int len=sum/UPLOAD_ROLE_BATCH_COUNT;
			if(sum%UPLOAD_ROLE_BATCH_COUNT!=0)
				len++;
			
			for(int i=0;i<len;i++)
			{
				List<Integer> ids=findIdByOnlineAndRole(source, i*UPLOAD_ROLE_BATCH_COUNT, UPLOAD_ROLE_BATCH_COUNT);
				ICachePipeline pipeline=getCacheHelper().getPipeline();
				for(Integer id:ids)
					pipeline.hset(getOnlineUserKey(id), "role", target, Constants.TIMEOUT_ONLINE_USER);
				pipeline.sync();
			}
		}
		return (int) getQueryHelper().update(new String[]{"role=?"}, new String[]{"role=?"}, new Object[]{target,source}, UserVo.class);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	public void updateFollowCount(int id,int count)
	{
		getCacheHelper().hincr(getIdKey(id), "follow_count", count);
		batchUpdate_queue("UPDATE "+Constants.DB_USER+" SET follow_count=follow_count+? WHERE id=?", new Object[]{count,id});
	}
	
	/**
	 * 更新粉丝数量
	 * @param id
	 * @param count
	 */
	public void updateFansCount(int id,int count)
	{
		getCacheHelper().hincr(getIdKey(id), "fans_count", count);
		batchUpdate_queue("UPDATE "+Constants.DB_USER+" SET fans_count=fans_count+? WHERE id=?", new Object[]{count,id});
	}
	
	/**
	 * 更新缓存
	 * @param userVo
	 */
	private boolean updateCache(int id,String fields[],Object values[])
	{
		return updateCache(Constants.CACHE_USER,id,fields,values,Constants.TIMEOUT_USER);
	}
	
	private String getIdKey(Object id)
	{
		return getKey(Constants.CACHE_USER,id);
	}
}